/**
 * XCE代码编辑器
 * author: imlzw
 * url: adai.imlzw.cn
 */

layui.define(['xTree', 'xAce', 'xUtils', 'element', 'layer', 'form'], function (exports) {
    let xTree = layui.xTree;
    let xAce = layui.xAce;
    let xUtils = layui.xUtils;
    let element = layui.element;
    let form = layui.form;
    let layer = layui.layer;
    let $ = layui.$;

    let XCE = function () {
        this.version = '1.0.0';
        this.renderIns = {};
        this.selectItem = {};
        this.options = {};
    }

    /**
     * 获取url
     * @param xceApi
     * @param type
     */
    function getUrl(xceApi, type, apiStyle) {
        if (apiStyle == "demo") {
            return xceApi + "/" + type;
        } else {
            let split = xceApi.indexOf("?") >= 0 ? "&" : "?";
            if(split == "&"){
                return xceApi + split + "oper=" + type;
            }
            return xceApi + split + "&oper=" + type;
        }
    }

    function saveFile(path, options, that) {
        if (options.readOnly) {
            return function (editor) {
                layer.msg("只读模式，无法保存文件！");
            };
        }
        return function (editor) {
            // 上传文件
            var blob = new Blob([editor.getValue()], {
                type: 'text/plain'
            });
            const file = new window.File(
                [blob],
                "1",
                {type: 'text/plain'}
            );
            var formData = new FormData();
            formData.append("file", file);
            formData.append("path", path);
            $.ajax({
                url: getUrl(options.api, "save", options.apiStyle),
                dataType: 'json',
                type: 'POST',
                async: false,
                data: formData,
                processData: false, // 使数据不做处理
                contentType: false, // 不要设置Content-Type请求头
                before: function () {
                    that.setStatus("正在保存文件...", true);
                },
                success: function (res) {
                    if (res.success) {
                        that.setStatus("保存文件成功！", true);
                    } else {
                        that.setStatus(res.message || "保存文件失败！", false);
                    }
                },
                error: function (rsp) {
                    console.log("保存文件错误", rsp)
                    that.setStatus("保存文件错误！" + rsp.status, false);
                }
            })

        };
    }

    /**
     * 节点点击事件
     * @param tabId
     * @param options
     * @param that
     * @returns {function(...[*]=)}
     */
    function nodeClick(tabId, options, that) {
        return function ({elem, state, data}) {
            that.selectItem[options.elem] = data;
            if (data.isFolder) {
                return;
            }
            if (!data.tabId) {
                data.tabId = data.id;
            }
            let layId = data.tabId;
            if (!$(`#${tabId} li[lay-id="${layId}"]`)[0]) {
                let url = getUrl(options.api, "content", options.apiStyle);
                url += (url.indexOf("?") >= 0 ? '&' : '?') + 'path=' + encodeURIComponent(data.path);
                let path = data.path;
                let fileType = that.getFileType(data.path);
                // if ("txt" == fileType) {
                //
                // } else
                if ("image" == fileType) {
                    element.tabAdd(tabId, {
                        title: data.title,
                        content: `<div class="x-ce-img-container" id="${layId}"><img class="x-ce-img_preview" src="${url}"></div>`,
                        id: layId,
                    });
                } else {
                    element.tabAdd(tabId, {
                        title: data.title,
                        content: `<div class="x-ce-xace-container" id="${layId}"></div>`,
                        id: layId,
                    });
                    $.get(url, function (data) {
                        let file = new File([data], "1");
                        var reader = new FileReader();
                        reader.readAsText(file, "utf-8");
                        reader.onload = function () {
                            //读取完毕后输出结果
                            let xceLang = that.getXceLang(that.getSuffix(path));
                            xAce.render({
                                id: layId,
                                theme: 'eclipse',
                                lang: xceLang,
                                initValue: this.result,
                                // 自定义命令
                                commands: [{
                                    name: 'save',
                                    bindKey: {
                                        win: "Ctrl-S",
                                        mac: "Command-S",
                                    },
                                    exec: saveFile(path, options, that)
                                }],
                                readOnly: options.readOnly
                            });
                        }
                    });
                    // element.tabAdd(tabId, {
                    //     title: data.title,
                    //     content: `<div class="x-ce-other-container" id="${layId}">未知类型文件，无法打开！</div>`,
                    //     id: layId,
                    // });
                }
            }
            element.tabChange(tabId, data.tabId);
        };
    }

    /**
     * 加载文件列表
     *
     * @param options
     * @param tabId
     * @param that
     */
    function loadList(options, that) {
        let tabId = options.tabId;
        $.ajax({
            url: getUrl(options.api, "list", options.apiStyle),
            methos: 'get',
            dataType: 'json',
            before: function () {
                that.setStatus("正在加载列表...", true);
            },
            success: function (res) {
                if (res && res.success) {
                    let render = xTree.render({
                        elem: '.x-ce-explorer-tree',  //绑定元素
                        showLine: true,
                        openIcon: 'layui-icon-triangle-d',
                        closeIcon: 'layui-icon-triangle-r',
                        leafIcon: 'layui-icon-file',
                        nodeOpenIcon: 'fa fa-folder-open',
                        nodeCloseIcon: 'fa fa-folder',
                        nodeIcon: 'fa fa-file',
                        // onlyIconControl: true,
                        data: res.data,
                        click: nodeClick(tabId, options, that),
                        dblclick: function ({elem, state, data}) {
                            // 显示修改文件路径与文件名的窗口
                        }
                    });
                    that.renderIns[options.elem + "_tree"] = render;
                    that.setStatus("加载列表完成！", true);
                } else {
                    console.log("加载列表失败！", res);
                    that.setStatus("加载列表失败！", false);
                }
            },
            error: function (rsp) {
                console.log("加载列表错误！", rsp)
                that.setStatus("加载列表错误！" + rsp.status, false);
            }
        })
    }


    /**
     * 显示状态
     */
    XCE.prototype.setStatus = function (txt, autoHide) {
        let $statusBar = $(this.options.elem + "  .x-ce-status-bar");
        $statusBar.text(txt);
        $statusBar.css("opacity", "1");
        let timeId = -1;
        if (autoHide) {
            timeId = setTimeout(function () {
                $statusBar.css("opacity", "0");
            }, 3000);
        }
        let that = this;
        if (that.statusTimeId > 0) {
            clearTimeout(that.statusTimeId);
        }
        that.statusTimeId = timeId;
    }


    /**
     * 删除文件
     *
     * @param that
     * @param options
     */
    function deleteFile(that, options) {
        if (options.readOnly) {
            return function (editor) {
                layer.msg("只读模式，无法删除文件！")
            };
        }
        let tabId = options.tabId;
        let selectItem = that.selectItem[options.elem];
        let isFolder = selectItem && (selectItem.isFolder || (selectItem.children && selectItem.children.length > 0));
        let treeIns = that.renderIns[options.elem + "_tree"];
        let pPath = "";
        let fileName = "";
        if (selectItem) {
            let lastIndexOf = selectItem.path.lastIndexOf("/");
            pPath = selectItem.path.substring(0, lastIndexOf);
            fileName = selectItem.path.substring(lastIndexOf + 1);
        } else {
            layer.msg("请选择要删除的文件或者目录！");
            return false;
        }
        //询问框
        layer.confirm(`是否删除${isFolder ? "目录" : "文件"} [${fileName}]？`, {
            btn: ['删除', '不删除'] //按钮
        }, function () {
            //发送节点到后台接口
            $.ajax({
                url: getUrl(options.api, "delete", options.apiStyle),
                data: {path: selectItem.path},
                method: "post",
                dataType: "json",
                before: function () {
                    that.setStatus("正在删除文件...", true);
                },
                success: function (res) {
                    if (res && res.success) {
                        that.setStatus("删除成功！", true);
                        let treeIns = that.renderIns[options.elem + "_tree"];
                        treeIns.deleteNode(selectItem.id);
                        element.tabDelete(tabId, selectItem.id);
                        clearSelect(options, that);
                        layer.close(layer.index);
                    } else {
                        that.setStatus("删除失败！" + ((res && res.msg) || ''), false);
                    }
                },
                error: function (rsp) {
                    console.log("删除错误！", rsp);
                    that.setStatus("删除错误！" + (rsp.status || ''), false);
                }

            });
        }, function () {
            layer.close(layer.index);
        });

    }

    /**
     * 编辑文件
     *
     * @param that
     * @param options
     */
    function editFile(that, options) {
        if (options.readOnly) {
            return function (editor) {
                layer.msg("只读模式，无法编辑文件！")
            };
        }
        let tabId = options.tabId;
        let selectItem = that.selectItem[options.elem];
        let isFolder = selectItem && (selectItem.isFolder || (selectItem.children && selectItem.children.length > 0));
        let treeIns = that.renderIns[options.elem + "_tree"];
        let pPath = "";
        let fileName = "";
        if (selectItem) {
            let lastIndexOf = selectItem.path.lastIndexOf("/");
            pPath = selectItem.path.substring(0, lastIndexOf);
            fileName = selectItem.path.substring(lastIndexOf + 1);
        } else {
            layer.msg("请选择要编辑的文件或者目录！");
            return false;
        }
        // 打开新建表单
        let dialogIndex = layer.open({
            title: "编辑" + (isFolder ? "目录" : "文件"),
            type: 1,
            maxmin: true,
            area: ["450px", "218px"],
            content: `
                    <form class="layui-form x-ce-dialog-form detail_form" action="">
                        <div class="layui-form-item">
                            <label class="layui-form-label">上级目录</label>
                            <div class="layui-input-block">
                              <input type="text" value="${pPath}" name="path" placeholder="上级目录"  autocomplete="off" class="layui-input">
                            </div>
                        </div> 
                        <div class="layui-form-item">
                            <label class="layui-form-label">${isFolder ? "目录" : "文件"}名称</label>
                            <div class="layui-input-block" >
                              <input type="text" value="${fileName}" name="file_name" placeholder="输入新${isFolder ? "目录" : "文件"}名" lay-verify="required" autocomplete="off" class="layui-input">
                            </div>
                        </div> 
                        <div class=" detail_form_footer">
                          <button class="layui-btn" lay-submit lay-filter="${options.elem}_editFileBtn">更新</button>
                        </div>
                    </form>
                `
        });

        //监听提交
        form.on(`submit(${options.elem}_editFileBtn)`, function (data) {
            let newFileTitle = data.field.file_name;
            let newPPath = data.field.path;
            newPPath = newPPath.length > 0 && newPPath.indexOf("/") != 0 ? "/" + newPPath : newPPath;
            let newFilePath = newPPath + '/' + data.field.file_name;
            newFilePath = newFilePath.replace("//", "/");
            let layId = newFilePath;
            // 判断文件是否存在
            if ($(`[data-id="${newFilePath}"]`, treeIns.config.elem)[0]) {
                layer.msg("目标文件已存在")
                return false;
            }
            //发送节点到后台接口
            $.ajax({
                url: getUrl(options.api, "move", options.apiStyle),
                data: {from: selectItem.path, to: newFilePath},
                method: "post",
                dataType: "json",
                before: function () {
                    that.setStatus("正在更新文件...", true);
                },
                success: function (res) {
                    if (res && res.success) {
                        refresh(options, that);
                        updateTabLayId(options, that, selectItem.path, newFilePath, isFolder);
                        that.setStatus("更新成功！", true);
                        layer.close(dialogIndex);
                    } else {
                        that.setStatus("更新失败！" + ((res && res.msg) || ''), false);
                    }
                },
                error: function (rsp) {
                    console.log("更新错误！", rsp);
                    that.setStatus("更新错误！" + (rsp.status || ''), false);
                }
            });
            return false;
        });
    }

    function updateTabLayId(options, that, oldPath, newPath, isFolder) {
        let tabId = options.tabId;
        if (isFolder) {
            let $lis = $(`[lay-filter="${tabId}"] > .layui-tab-title > li`);
            for (let idx = 0; idx <= $lis.length; idx++) {
                let $li = $($lis[idx]);
                let layId = $li.attr("lay-id");
                if (layId.indexOf(oldPath) == 0) {
                    $li.attr("lay-id", layId.replace(oldPath, newPath));
                }
            }
        } else {
            let $li = $(`[lay-filter="${tabId}"] > .layui-tab-title > li[lay-id="${oldPath}"]`);
            $li.attr("lay-id", newPath);
            let $children = $li.children().clone(true);
            let index = newPath.lastIndexOf("/");
            $li.text(newPath.substring(index + 1)).append($children);
        }
    }


    /**
     * 新建文件
     *
     * @param that
     * @param options
     */
    function newFile(that, options) {
        if (options.readOnly) {
            return function (editor) {
                layer.msg("只读模式，无法创建新文件！")
            };
        }
        let tabId = options.tabId;
        let selectItem = that.selectItem[options.elem];
        let isFolder = selectItem && (selectItem.isFolder || (selectItem.children && selectItem.children.length > 0));
        let treeIns = that.renderIns[options.elem + "_tree"];
        let pPath = "";
        if (selectItem) {
            if (isFolder) {
                pPath = selectItem.path;
            } else {
                let lastIndexOf = selectItem.path.lastIndexOf("/");
                pPath = selectItem.path.substring(0, lastIndexOf);
            }
        }
        let fileName = "新文件";
        // 打开新建表单
        let dialogIndex = layer.open({
            title: "新建文件",
            type: 1,
            maxmin: true,
            area: ["450px", "218px"],
            content: `
                    <form class="layui-form x-ce-dialog-form detail_form" action="">
                        <div class="layui-form-item">
                            <label class="layui-form-label">上级目录</label>
                            <div class="layui-input-block" >
                              <input type="text" value="${pPath}" name="path" placeholder="上级目录"  autocomplete="off" class="layui-input">
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">名称</label>
                            <div class="layui-input-block" >
                              <input type="text" value="${fileName}" name="file_name" placeholder="输入名称" lay-verify="required" autocomplete="off" class="layui-input">
                            </div>
                        </div>
                        <div class=" detail_form_footer">
                          <button class="layui-btn" lay-submit lay-filter="${options.elem}_newFileBtn">创建文件</button>
                        </div>
                    </form>
                `
        });

        //监听提交
        form.on(`submit(${options.elem}_newFileBtn)`, function (data) {
            let newFileTitle = data.field.file_name;
            let pPath = data.field.path;
            pPath = pPath.length > 0 && pPath.indexOf("/") != 0 ? "/" + pPath : pPath;
            let newFileId = pPath + '/' + data.field.file_name;
            newFileId = newFileId.replace("//", "/");
            let layId = newFileId;
            // 判断文件是否存在
            if ($(`[data-id="${newFileId}"]`, treeIns.config.elem)[0]) {
                layer.msg("目标文件已存在")
                return false;
            }
            // 判断并构建父节点
            let pp = pPath;
            let $pPack = $(`[data-id="${pp}"] > .layui-tree-pack`, treeIns.config.elem);
            let pItem = null;
            let firstItem = null;
            // 判断父节点是否存在
            while (!$pPack[0]) {
                let lastIndexOf = pp.lastIndexOf("/");
                if (lastIndexOf >= 0) {
                    pp = pp.substring(0, lastIndexOf);
                    $pPack = $(`[data-id="${pp}"] > .layui-tree-pack`, treeIns.config.elem);
                } else {
                    break;
                }
            }
            let hasParent = !!$pPack[0];
            // 判断是否需要添加路径中的父节点
            let $treeRoot = treeIns.config.elem.find(".layui-tree");
            if (pp != pPath) {
                $pPack = hasParent ? $pPack : $treeRoot;
                let nodes = pPath.replace(pp, '').split("/");
                for (let idx = 0; idx < nodes.length; idx++) {
                    let nPath = nodes[idx];
                    if (!nPath) continue;
                    let path = pItem && pItem.path ? pItem.path + "/" + nPath : "/" + nPath;
                    let newItem = {
                        title: nPath,
                        path: path,
                        id: path,
                        spread: true,
                        isFolder: true,
                        children: [],
                    };
                    if (pItem) {
                        pItem.children.push(newItem);
                    }
                    if (!firstItem) {
                        newItem.id = pp + path;
                        newItem.path = pp + path;
                        firstItem = newItem;
                    }
                    pItem = newItem;
                }
            }
            // 目标节点
            let newItem = {
                id: newFileId,
                title: newFileTitle,
                path: newFileId,
                tabId: layId,
            };
            // 存在父节点时
            if (pItem) {
                pItem.children.push(newItem);
                newItem = firstItem;
            }
            //todo 发送节点到后台接口
            $.ajax({
                url: getUrl(options.api, "create", options.apiStyle),
                data: {path: newFileId},
                method: "post",
                dataType: "json",
                before: function () {
                    that.setStatus("正在创建文件...", true);
                },
                success: function (res) {
                    if (res && res.success) {
                        that.setStatus("文件创建成功！", true);
                        // 调用树添加节点接口
                        treeIns.addNode(pp, newItem);
                        element.tabAdd(tabId, {
                            title: newFileTitle,
                            content: `<div class="x-ce-xace-container" id="${layId}"></div>`,
                            id: layId,
                        });
                        xAce.render({
                            id: layId,
                            theme: 'eclipse',
                            lang: 'txt',
                            // 自定义命令
                            commands: [{
                                name: 'save',
                                bindKey: {
                                    win: "Ctrl-S",
                                    mac: "Command-S",
                                },
                                exec: saveFile(newFileId, options, that)
                            }]
                        });
                        // 定位tab页
                        element.tabChange(tabId, layId);
                        // 展开目录
                        if ($pPack[0]) {
                            let $parents = $pPack.parents(".layui-tree-set");
                            for (var idx = 0; idx < $parents.length; idx++) {
                                let $parent = $($parents[idx]);
                                if (!$parent.hasClass("layui-tree-spread")) {
                                    $(" > .layui-dir-node:first > .layui-tree-main > .layui-tree-iconClick > i", $parent).click();
                                }
                            }
                        }
                        layer.close(dialogIndex);
                    } else {
                        that.setStatus("文件创建失败！" + ((res && res.msg) || ''));
                    }
                },
                error: function (rsp) {
                    console.log("文件创建错误！", rsp)
                    that.setStatus("文件创建错误！" + (rsp.status || ''));
                }
            });
            return false;
        });
    }

    function closeAllTab(options) {
        let tabId = options.tabId;
        let $lis = $(`[lay-filter="${tabId}"] > .layui-tab-title > li`);
        for (let idx = 0; idx <= $lis.length; idx++) {
            let $li = $($lis[idx]);
            let layId = $li.attr("lay-id");
            element.tabDelete(tabId, layId);
        }
    }

    function refresh(options, that) {
        loadList(options, that);
        clearSelect(options, that);
    }

    function clearSelect(options, that) {
        delete that.selectItem[options.elem]
    }

    /**
     * 初始化事件
     * @param $root
     * @param options
     * @param tabId
     */
    XCE.prototype.initEvents = function (options) {
        let that = this;
        // 新建文件按钮事件
        $(".file-oper-newfile", options.root).click(function (e) {
            newFile(that, options);
        }).css("display", options.readOnly ? "none" : "");
        $(".file-oper-edit", options.root).click(function (e) {
            editFile(that, options);
        }).css("display", options.readOnly ? "none" : "");
        $(".file-oper-delete", options.root).click(function (e) {
            deleteFile(that, options);
        }).css("display", options.readOnly ? "none" : "");
        $(".file-oper-refresh", options.root).click(function (e) {
            refresh(options, that);
        });
        $(".file-oper-collapse", options.root).click(function (e) {
            options.root.find(".x-tree-focus").css("display", "none");
            $(".layui-tree-spread > .layui-dir-node > .layui-tree-main > .layui-tree-iconClick > i", options.root).click();
        });
        // 拖动效果
        $(".x-ce-split", options.root).on("mousedown", function (ev) {
            var ev = ev || window.event;
            that.disX = ev.clientX; // 获取鼠标按下时光标x的值
            let $explorer = $(".x-ce-file-explorer", options.root);
            let $main = $(".x-ce-file-main", options.root);
            let explorerRect = $explorer[0].getBoundingClientRect();
            let mainRect = $main[0].getBoundingClientRect();
            that.disW = explorerRect.width; // 获取拖拽前div的宽
            let $this = $(this);
            let moveEvent = function (ev) {
                var ev = ev || window.event;
                var explorerWidth = ev.clientX - that.disX + that.disW;
                if (explorerWidth < 200) {
                    explorerWidth = 200;
                }
                $explorer.css("width", explorerWidth + 'px');
                $main.css("width", `calc(100% - ${explorerWidth + 2}px`);
            };
            $(document).bind("mousemove", moveEvent).bind("mouseup", function (ev) {
                $(document).unbind("mousemove", moveEvent);
            })
        });
    }

    XCE.prototype.render = function (options) {
        let that = this;
        this.options = options;
        let base = layui.cache.modules.xce.replace("xce.js", "") || '';
        xUtils.loadCss(base + "xce.css");
        let $root = $(options.elem);
        let tabId = options.tabId = "tab_" + new Date().getTime();
        let $editor = $(`
        <div class="x-code-editor">
            <div class="x-ce-menus ">
                <div class="x-ce-nav-logo"><a href="https://gitee.com/imlzw/xce">XCE代码编辑器</a></div>
            </div>
            <div class="x-ce-file-explorer">
                <div class="x-ce-explorer-title">
                    <div class="x-ce-explorer-title-txt">浏览器</div>
                    <div class="x-ce-context-menu" >
                        <div class="x-ce-menu-item file-oper-newfile" title="新建文件">
                            <svg viewBox="0 0 1024 1024" width="1em" height="1em" fill="currentColor"><path d="M896 243.8v12.2H640V0h12.2c12.8 0 25 5 34 14l195.8 196c9 9 14 21.2 14 33.8zM624 320h272v656c0 26.6-21.4 48-48 48H176c-26.6 0-48-21.4-48-48V48C128 21.4 149.4 0 176 0h400v272c0 26.4 21.6 48 48 48z m96 280c0-13.2-10.8-24-24-24h-120v-120c0-13.2-10.8-24-24-24h-80c-13.2 0-24 10.8-24 24v120h-120c-13.2 0-24 10.8-24 24v80c0 13.2 10.8 24 24 24h120v120c0 13.2 10.8 24 24 24h80c13.2 0 24-10.8 24-24v-120h120c13.2 0 24-10.8 24-24v-80z"></path></svg>
                        </div>
                        <!--<div class="x-ce-menu-item file-oper-newfolder" title="新建目录">
                            <svg viewBox="0 0 1024 1024" width="1em" height="1em" fill="currentColor"><path d="M576 256l-128-128-448 0 0 832 1024 0 0-704-448 0zM704 704l-128 0 0 128-128 0 0-128-128 0 0-128 128 0 0-128 128 0 0 128 128 0 0 128z"></path></svg>
                        </div>-->
                       <!-- <div class="x-ce-menu-item file-oper-import" title="导入文件">
                            <svg viewBox="0 0 1024 1024" width="1em" height="1em" fill="currentColor"><path d="M388.23384594 32v324.03692344L137.6 353.00923062l380.30769187 386.95384594 371.37230813-389.90769187H638.79384594V32H388.23384594z m498.09230812 744v72H137.67384594v-72H32V992h960v-216h-105.67384594z" ></path></svg>
                        </div>-->
                        <div class="x-ce-menu-item file-oper-edit" title="编辑">
                            <svg viewBox="0 0 1024 1024" width="1em" height="1em" fill="currentColor"><path d="M956.559566 257.360749c-21.536979-35.583965-48.086953-70.423931-80.574921-102.7269-32.854968-32.611968-68.316933-59.345942-104.576898-80.850921l63.734937-63.678938s92.14691-0.031 138.250865 46.070955c46.038955 46.102955 46.038955 138.279865 46.038955 138.279865l-62.872938 62.905939zM388.96512 833.183186H196.384308v-192.579812l23.145978-23.112977c39.110962 18.440982 77.970924 44.493957 112.999889 79.487922 35.023966 34.995966 61.07894 73.948928 79.516923 113.06089l-23.081978 23.143977zM903.339618 310.609697L467.683043 754.468263c-22.524978-37.190964-50.247951-73.577928-84.161918-107.306895-34.344966-34.097967-71.41093-61.976939-109.222893-84.437918L718.991798 126.259877c37.437963 17.637983 74.692927 42.546958 108.232894 76.086925 33.540967 33.538967 58.413943 70.731931 76.114926 108.262895zM132.275371 136.843866v760.419258h760.421257V580.419433l126.734876-126.734876v478.141533c0 50.92795-41.21596 92.17391-92.204909 92.17391H97.682405C46.750454 1023.999 5.540495 982.75304 5.540495 931.82509V102.2799c0-50.95795 41.21096-92.20591 92.14291-92.20591l478.170533 0.031-126.734877 126.738876H132.275371z" ></path></svg>
                        </div>
                        <div class="x-ce-menu-item file-oper-delete" title="删除">
                            <svg viewBox="0 0 1024 1024" width="1em" height="1em" fill="currentColor"><path d="M860.29743713 91.73649423L679.0620783 91.73649423 627.28054825 39.95496296 368.37289311 39.95496296 316.59136307 91.73649423 135.35600423 91.73649423 135.35600423 195.29955555 860.29743713 195.29955555M187.13753549 868.45945719C187.13753549 925.41914074 233.74091326 972.02251853 290.70059682 972.02251853L704.95284454 972.02251853C761.91252809 972.02251853 808.51590587 925.41914074 808.51590587 868.45945719L808.51590587 247.08108682 187.13753549 247.08108682 187.13753549 868.45945719Z" ></path></svg>
                        </div>
                        <div class="x-ce-menu-item file-oper-refresh" title="刷新列表">
                            <svg viewBox="0 0 1024 1024" width="1em" height="1em" fill="currentColor"><path d="M949.948959 146.249899l0 255.82655c0 21.980617-13.988596 35.969213-35.969213 35.969213l-255.82655 0c-13.988596 0-25.982768-7.992021-33.972742-21.980617-5.997598-13.988596-4.001127-27.977191 7.990998-39.97034l79.941704-77.945233c-55.954383-51.973722-121.917724-77.955466-199.862957-77.955466-37.974893 0-75.949786 8.002254-113.924679 21.99085-37.974893 15.984043-67.947532 37.974893-91.933829 63.956637-25.981744 23.986297-47.972595 53.958936-63.956637 91.933829-29.982872 73.954339-29.982872 153.895019 0 227.849358 15.984043 37.975916 37.974893 67.947532 63.956637 91.933829 23.986297 25.982768 53.958936 47.973618 91.933829 63.956637 37.974893 13.988596 75.949786 21.99085 113.924679 21.99085 45.966914 0 87.941911-9.997702 127.913275-29.981848 41.97602-17.989723 75.950809-45.966914 101.930507-83.942831 7.993045-4.001127 11.994172-5.995551 13.988596-5.995551 5.997598 0 9.998725 1.994424 13.988596 5.995551l77.957513 77.945233c3.988848 4.001127 5.986341 7.993045 5.986341 11.994172 0 1.994424-1.99647 5.995551-3.990894 11.994172-43.972491 51.962465-93.940532 91.933829-151.898549 117.91455-53.958936 25.982768-115.921149 39.971363-185.874361 39.971363-61.96119 0-119.921253-11.983939-169.889295-33.972742C284.40084 889.74325 236.438479 857.764931 202.464713 821.785485c-35.979446-33.972742-67.957765-81.936127-93.939509-139.897214-45.966914-101.930507-45.966914-237.846036 0-339.777567 25.981744-57.960063 57.960063-105.922425 93.939509-139.89619 33.973766-35.979446 81.936127-67.957765 139.89619-93.939509 49.968042-21.99085 107.928105-33.973766 169.889295-33.973766 55.963593 0 109.923552 9.987468 161.886017 29.972639 53.969169 21.99085 101.932554 51.963489 139.907447 89.938382l73.954339-73.944106c9.987468-9.997702 23.987321-13.988596 39.971363-8.002254C941.956937 120.268154 949.948959 132.261303 949.948959 146.249899z" ></path></svg>
                        </div>
                        <div class="x-ce-menu-item file-oper-collapse" title="全部收缩">
                            <svg viewBox="0 0 1025 1024" width="1em" height="1em" fill="currentColor"><path d="M62 62v900h901.35V62H62z m772.65 528.3H190.7V461.6h643.95v128.7z"></path></svg>
                        </div>
                    </div>
                </div>
                <div class="x-ce-explorer-tree"></div>
            </div>
            <div class="x-ce-split"></div>
            <div class="x-ce-file-main">
                <div class="x-ce-tabs layui-tab" lay-allowClose="true" id="${tabId}" lay-filter="${tabId}">
                    <ul class="layui-tab-title">
                    </ul>
                    <div class="layui-tab-content">
                    </div>
                </div>
            </div>
            <div class="x-ce-status-bar">
                
            </div>
        </div>
        `);
        $root.append($editor);
        element.render(tabId);

        loadList(options, that);
        options.root = $root;
        that.initEvents(options);
        that.renderIns[options.elem] = options;
        return options;
    }

    /**
     * 获取文件后缀名
     *
     * @param path
     * @returns {string}
     */
    XCE.prototype.getSuffix = function (path) {
        if (path) {
            var idx = path.lastIndexOf(".");
            if (idx >= 0) {
                return path.substring(idx + 1);
            }
        }
        return '';
    };

    let langs = {
        "css": ["css", "less"],
        "javascript": ["js"],
        "html": ["html", "htm"],
        "java": ["java"],
        "json": ["json"],
        "jsp": ["jsp"],
        "jsx": ["jsx"],
        "markdown": ["md"],
        "perl": ["perl"],
        "php": ["php"],
        "powershell": ["ps"],
        "python": ["py"],
        "scala": ["scala"],
        "sh": ["sh"],
        "sql": ["sql"],
        "xml": ["xml"],
        "yaml": ["yaml"],
    }

    /**
     * 根据后缀获取语言类型
     * @param suffix
     * @returns {string}
     */
    XCE.prototype.getXceLang = function (suffix) {
        let toLowerCase = suffix.toLowerCase();
        for (let langsKey in langs) {
            for (let idx in langs[langsKey]) {
                if (toLowerCase == langs[langsKey][idx]) {
                    return langsKey;
                }
            }
        }
        return 'java';
    };


    let imgExtRegx = /^(art|bmp|dib|gif|ico|ief|jpe|jpeg|jpg|mac|pbm|pct|pgm|pic|pict|png|pnm|pnt|ppm|psd|qti|qtif|ras|rgb|svg|svgz|tif|tiff|wbmp|xbm|xpm|xwd)$/i;
    let txtExtRegx = /^(js|css|json|txt|html|htm|jsp|jsx|tsx|py|php|java|xml|yaml|sql|sh|bash|stl)$/i;

    XCE.prototype.getFileType = function (path) {
        let suffix = this.getSuffix(path);
        if (imgExtRegx.test(suffix)) {
            return 'image';
        } else if (txtExtRegx.test(suffix)) {
            return 'txt';
        } else {
            return 'other';
        }
    };


    exports('xce', new XCE());
});